package com.magina.machine.config.persister;

import com.alibaba.fastjson.JSON;
import com.magina.machine.model.ApproveEvent;
import com.magina.machine.model.ApproveStatus;
import com.magina.machine.model.DemoClass;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.StateMachineContext;
import org.springframework.statemachine.StateMachineException;
import org.springframework.statemachine.persist.AbstractPersistingStateMachineInterceptor;
import org.springframework.statemachine.persist.StateMachineRuntimePersister;
import org.springframework.statemachine.state.State;
import org.springframework.statemachine.support.DefaultExtendedState;
import org.springframework.statemachine.support.DefaultStateMachineContext;
import org.springframework.statemachine.support.StateMachineInterceptor;
import org.springframework.statemachine.transition.Transition;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component("approveRedisPersister")
//@ConditionalOnProperty(value = "statemachine.persister", havingValue = "redis")
public class ApproveRedisPersister extends AbstractPersistingStateMachineInterceptor<ApproveStatus, ApproveEvent, String>
        implements StateMachineRuntimePersister<ApproveStatus, ApproveEvent, String> {

    @Autowired
    private RedissonClient reRedisson;

    @Override
    public void preStateChange(State<ApproveStatus, ApproveEvent> state, Message<ApproveEvent> message,
                               Transition<ApproveStatus, ApproveEvent> transition, StateMachine<ApproveStatus, ApproveEvent> stateMachine) {
        try {
            log.info("==>enter preStateChange()");
            StateMachineContext<ApproveStatus, ApproveEvent> context = new DefaultStateMachineContext<ApproveStatus, ApproveEvent>(state.getId(),
                    null, new HashMap<>(), new DefaultExtendedState(), null, stateMachine.getId());
            context.getEventHeaders().put("demoClass", message.getHeaders().get("demoClass"));
            write(context, stateMachine.getId());
        } catch (Exception e) {
            throw new StateMachineException("Unable to persist stateMachineContext", e);
        }
    }

    @Override
    public void write(StateMachineContext<ApproveStatus, ApproveEvent> context, String stateMachineId) throws Exception {
        if (context.getState() != null) {
            DemoClass demoClass = (DemoClass) context.getEventHeaders().get("demoClass");
            ApproveStatus state = context.getState();
            demoClass.setStatus(context.getState().name());
            log.info("==>approveRedisPersister write: data is {},state: {}", JSON.toJSONString(demoClass), state);
            RMap<String, DemoClass> agentCurrentStatusMap = reRedisson.getMap(stateMachineId);
            agentCurrentStatusMap.put(stateMachineId, demoClass);
        }
    }

    @Override
    public StateMachineContext<ApproveStatus, ApproveEvent> read(String stateMachineId) throws Exception {
        Map<String, DemoClass> agentCurrentStatusMap = reRedisson.getMap(stateMachineId);
        DemoClass demoClass = agentCurrentStatusMap.get(stateMachineId);
        DefaultStateMachineContext<ApproveStatus, ApproveEvent> stateMachineContext = null;
        if (demoClass == null) {
            log.info("==>approveRedisPersister read: stateMachineId is {}, read miss", stateMachineId);
            stateMachineContext = new DefaultStateMachineContext<ApproveStatus, ApproveEvent>(ApproveStatus.DRAFT,
                    null, new HashMap<>(), new DefaultExtendedState(), null, stateMachineId);
        } else {
            log.info("==>approveRedisPersister read: stateMachineId is {}, read hit", stateMachineId);
            stateMachineContext = new DefaultStateMachineContext<ApproveStatus, ApproveEvent>(ApproveStatus.valueOf(demoClass.getStatus()),
                    null, new HashMap<>(), new DefaultExtendedState(), null, stateMachineId);
        }
        return stateMachineContext;
    }

    @Override
    public StateMachineInterceptor<ApproveStatus, ApproveEvent> getInterceptor() {
        return this;
    }
}
